/*
 *  Copyright (C) 2010 Matthias Buch-Kromann <mbk.isv@cbs.dk>
 * 
 *  This file is part of the MatrixParser package.
 *  
 *  The MatrixParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.osdtsystem.matrixparser.featureextraction;

import java.util.List;
import org.osdtsystem.matrixparser.data.CONLLSentence;
import org.osdtsystem.matrixparser.data.CONLLToken;
import org.osdtsystem.matrixparser.parsers.output.DependencyTree;
import org.osdtsystem.matrixparser.features.FeatureVector;
import org.osdtsystem.matrixparser.parsers.ParsingModel;

/**
 *
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
public class HigherOrderMbkLocalOrder extends AbstractHigherOrderExtractor {
    // Genes
    final static String name = "localorder";
    final static int genes = 175;

    public HigherOrderMbkLocalOrder(ParsingModel model) {
        super(model, name, genes);
    }

    public void extractHigherOrder(FeatureVector fv, DependencyTree tree, int inode) {
        // Starting gene
        int gene = firstGene();

        // Process all left dependents
        CONLLSentence sentence = tree.sentence();
        int ihead = tree.head(inode);
        if (ihead < 0)
            return;

        // Find node and head
        CONLLToken land = sentence.get(inode);
        CONLLToken head = sentence.get(ihead);

        // Find head features
        String postag = onMulti(gene++) ? head.postag() : "";
        String cpostag = onMulti(gene++) ? head.postag() : "";
        String form = onMulti(gene++) ? head.form() : "";
        String lemma = onMulti(gene++) ? head.lemma() : "";
        String landLab = onMulti(gene++) ? tree.labelName(inode) : "";
        String headLab = onMulti(gene++) ? tree.labelName(ihead) : "";

        // Find sibling indices
        List<Integer> children = inode < ihead ? tree.leftChildren(ihead) : tree.rightChildren(ihead);
        int nodeIndex = children.indexOf(inode);
        int cprevIndex = tree.prevComplement(children, nodeIndex - 1);
        int aprevIndex = tree.adjacentAdjunct(children, nodeIndex - 1);
        int anextIndex = tree.adjacentAdjunct(children, nodeIndex + 1);
        int cnextIndex = tree.nextComplement(children, nodeIndex + 1);

        // Find sibling ids
        int icprev = cprevIndex >= 0 ? children.get(cprevIndex) : -1;
        int iaprev = aprevIndex >= 0 ? children.get(aprevIndex) : -1;
        int ianext = anextIndex >= 0 ? children.get(anextIndex) : -1;
        int icnext = cnextIndex >= 0 ? children.get(cnextIndex) : -1;

        // Find labels
        String cprevLab = onMulti(gene++) && icprev >= 0 ? tree.labelName(icprev) : "_";
        String aprevLab = onMulti(gene++) && iaprev >= 0 ? tree.labelName(iaprev) : "_";
        String anextLab = onMulti(gene++) && ianext >= 0 ? tree.labelName(ianext) : "_";
        String cnextLab = onMulti(gene++) && icnext >= 0 ? tree.labelName(icnext) : "_";

        // Find token features
        //String landLemma = land.lemma();
        String landPos = onMulti(gene++) ? land.postag() : "";
        String landCpos = onMulti(gene++) ? land.cpostag() : "";

        // Add features: both left and right simultaneously
        String[] contexts = {"", cpostag, postag, headLab, lemma, form};
        for (String context : contexts) {
            if (on(gene++)) add(fv, "land:Ll#l#lL", context, cprevLab, aprevLab, landLab, anextLab, cnextLab);
            if (on(gene++)) add(fv, "land:L#l#L", context, cprevLab, landLab, cnextLab);
            if (on(gene++)) add(fv, "land:l#l#l", context, aprevLab, landLab, anextLab);
            if (on(gene++)) add(fv, "land:Ll#lc#lL", context, cprevLab, aprevLab, landLab, landCpos, anextLab, cnextLab);
            if (on(gene++)) add(fv, "land:L#lc#L", context, cprevLab, landLab, landCpos, cnextLab);
            if (on(gene++)) add(fv, "land:l#lc#l", context, aprevLab, landLab, landCpos, anextLab);
            if (on(gene++)) add(fv, "land:Ll#lp#lL", context, cprevLab, aprevLab, landLab, landPos, anextLab, cnextLab);
            if (on(gene++)) add(fv, "land:L#lp#L", context, cprevLab, landLab, landPos, cnextLab);
            if (on(gene++)) add(fv, "land:l#lp#l", context, aprevLab, landLab, landPos, anextLab);

            // Left only
            if (on(gene++)) add(fv, "land:Ll#l#", context, cprevLab, aprevLab, landLab);
            if (on(gene++)) add(fv, "land:L#l#", context, cprevLab, landLab);
            if (on(gene++)) add(fv, "land:l#l#", context, aprevLab, landLab);
            if (on(gene++)) add(fv, "land:Ll#lc#", context, cprevLab, aprevLab, landLab, landCpos);
            if (on(gene++)) add(fv, "land:L#lc#", context, cprevLab, landLab, landCpos);
            if (on(gene++)) add(fv, "land:l#lc#", context, aprevLab, landLab, landCpos);
            if (on(gene++)) add(fv, "land:Ll#lp#", context, cprevLab, aprevLab, landLab, landPos);
            if (on(gene++)) add(fv, "land:L#lp#", context, cprevLab, landLab, landPos);
            if (on(gene++)) add(fv, "land:l#lp#", context, aprevLab, landLab, landPos);

            // Right only
            if (on(gene++)) add(fv, "land:#l#lL", context, landLab, anextLab, cnextLab);
            if (on(gene++)) add(fv, "land:#l#L", context, landLab, cnextLab);
            if (on(gene++)) add(fv, "land:#l#l", context, landLab, anextLab);
            if (on(gene++)) add(fv, "land:#lc#lL", context, landLab, landCpos, anextLab, cnextLab);
            if (on(gene++)) add(fv, "land:#lc#L", context, landLab, landCpos, cnextLab);
            if (on(gene++)) add(fv, "land:#lc#l", context, landLab, landCpos, anextLab);
            if (on(gene++)) add(fv, "land:#lp#lL", context, landLab, landPos, anextLab, cnextLab);
            if (on(gene++)) add(fv, "land:#lp#L", context, landLab, landPos, cnextLab);
            if (on(gene++)) add(fv, "land:#lp#l", context, landLab, landPos, anextLab);
        }

        // Update gene count
        setLastGene(gene);

        // We only want unknown counted once
        if (fv.getValue(featureHandler.UNKNOWN) != 0)
            fv.setValue(featureHandler.UNKNOWN, 1);
    }
}
